﻿using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;

namespace DimensionsHelper.LanguageService.Syntax;

public class ParameterSignature : BindableSignature
{
    private IntegerLiteral?[] _boundaries;
    private Expression? _defaultValue;
    private SyntaxToken? _equalToken;
    private SyntaxList<SyntaxToken>? _modifiers;

    internal ParameterSignature(Identifier name, SyntaxNode? parent) :
        base(SyntaxKinds.ParameterSignature, SyntaxToken.Default, name, parent)
    {
        _boundaries = [];
        _defaultValue = EmptyExpression.Default;
    }


    /// <summary>
    ///     Optional 关键字
    /// </summary>
    public SyntaxToken? OptionalKeywordToken { get; private set; }


    /// <summary>
    ///     ParamArray 关键字
    /// </summary>
    public SyntaxToken? ParamArrayKeywordToken { get; private set; }


    /// <summary>
    ///     数组维度数
    /// </summary>
    public int Rank { get; set; }


    /// <summary>
    ///     ='等号Token
    /// </summary>
    public SyntaxToken? EqualToken => _equalToken;


    /// <summary>
    ///     参数的默认值表达式，如果未配置，此值是<see cref="Nullable" />
    /// </summary>
    public Expression? DefaultValue => _defaultValue;


    protected override string GetFullName()
    {
        Debug.Assert(Parent != null);
        return Parent == null ? Name : $"{((SignatureWithParameters)Parent).FullName}.{Name}";
    }


    public override bool ContainsModifier(SyntaxKinds kind)
    {
        return kind switch
        {
            SyntaxKinds.OptionalKeywordToken => OptionalKeywordToken != null,
            SyntaxKinds.ParamArrayKeywordToken => ParamArrayKeywordToken != null,
            _ => false
        };
    }


    public override bool ContainsAnyModifier(params SyntaxKinds[] modifiersKinds)
    {
        return _modifiers?.Any(token => Array.IndexOf(modifiersKinds, token.Kind) >= 0) == true;
    }

    /// <summary>
    ///     设置指定维度的数组长度定义
    /// </summary>
    public void SetArrayBoundary(int rank, IntegerLiteral? boundary)
    {
        if (rank < 1)
        {
            return;
        }

        if (rank > _boundaries.Length)
        {
            Array.Resize(ref _boundaries, rank);
        }
        else
        {
            IntegerLiteral? oldBound = _boundaries[rank - 1];
            if (oldBound != null)
            {
                oldBound.Parent = null;
            }
        }

        _boundaries[rank - 1] = boundary;

        if (boundary != null)
        {
            boundary.Parent = this;
        }
    }

    /// <summary>
    ///     尝试获取指定维度的长度定义，并将查找到的值赋值给<paramref name="bound" />中。
    /// </summary>
    public bool TryGetArrayBoundary(int rank, [MaybeNullWhen(false)] out IntegerLiteral bound)
    {
        bound = null;

        if (rank <= 0 || rank > _boundaries.Length)
        {
            return false;
        }

        IntegerLiteral? def = _boundaries[rank - 1];

        if (def == null)
        {
            return false;
        }

        bound = def;
        return true;
    }


    /// <summary>
    ///     不检查前缀是否有效，添加到前缀列表中
    /// </summary>
    public void AddModifier(SyntaxToken modifier)
    {
        AddChildMember(ref _modifiers, modifier);

        if (modifier.IsNode(SyntaxKinds.OptionalKeywordToken))
        {
            OptionalKeywordToken = modifier;
        }
        else if (modifier.IsNode(SyntaxKinds.ParamArrayKeywordToken))
        {
            ParamArrayKeywordToken = modifier;
        }
    }


    /// <summary>
    ///     检查是否是有效的参数前缀并添加到前缀列表中。
    /// </summary>
    public bool TryAddModifier(SyntaxToken modifier)
    {
        if (!modifier.IsOneOfNode(SyntaxKinds.OptionalKeywordToken, SyntaxKinds.ParamArrayKeywordToken))
        {
            return false;
        }

        if (modifier.IsNode(SyntaxKinds.OptionalKeywordToken))
        {
            OptionalKeywordToken = modifier;
        }
        else
        {
            ParamArrayKeywordToken = modifier;
        }

        AddChildMember(ref _modifiers, modifier);
        return true;
    }


    public void Update(SyntaxToken equalToken, Expression initValue)
    {
        SetChildNullableField(ref _equalToken, SyntaxToken.IsNullOrEmpty, equalToken);
        SetChildNullableField(ref _defaultValue, Expression.IsEmptyExpression, initValue);
    }


    public override void AcceptVisitor<T>(SyntaxNodeVisitor<T> visitor)
    {
        Accept(visitor, OptionalKeywordToken, ParamArrayKeywordToken);
        base.AcceptVisitor(visitor);
        Accept(visitor, EqualToken, DefaultValue);
    }
}


public static partial class NodeFactory
{
    public static ParameterSignature CreateParameterSignature(SyntaxNode? parent, Identifier name,
        SyntaxToken[]? modifiers, SyntaxToken? equalToken, Expression? defaultValue)
    {
        Debug.Assert((equalToken == null && defaultValue == null) || (equalToken != null &&
                                                                      equalToken.IsNode(SyntaxKinds.EqualToken) &&
                                                                      defaultValue != null &&
                                                                      !Expression.IsEmptyExpression(defaultValue)));
        ParameterSignature signature = new(name, parent);

        if (modifiers != null)
        {
            foreach (SyntaxToken modifier in modifiers)
            {
                signature.AddModifier(modifier);
            }
        }

        if (defaultValue != null && equalToken != null)
        {
            signature.Update(equalToken, defaultValue);
        }

        return signature;
    }
}